package com.hare.system_server.serice.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hare.auth.base.BaseLoginUser;
import com.hare.auth.utils.JwtUtils;
import com.hare.common.exception.PasswordNotMatchException;
import com.hare.common.exception.ServiceException;
import com.hare.common.global.Audience;
import com.hare.common.global.constant.BaseConstant;
import com.hare.common.utils.DateTimeUtils;
import com.hare.common_redis.RedisCache;
import com.hare.system_api.dto.SysUserDTO;
import com.hare.system_api.po.SysAdmin;
import com.hare.system_server.mapper.SysUserMapper;
import com.hare.system_server.serice.SysUserLoginService;

import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @program: Hare
 * @description: 登录实现Service
 * @author: Hare
 * @create: 2022-06-19 15:59
 * @Version 6.0.1
 **/
@Service
public class SysUserLoginServiceImpl extends ServiceImpl<SysUserMapper, SysAdmin> implements SysUserLoginService {

    @Autowired
    Audience audience;

    @Autowired
    AuthenticationManager authenticationManager;

    @Autowired
    RedisCache redisCache;

    @Autowired
    SysUserMapper sysUserMapper;

    /**
     * 后台管理登录处理
     *
     * @param loginUserDTO 用户账号密码
     * @return token
     */
    @Override
    public Map<String, Object> adminLogin(SysUserDTO loginUserDTO) {
        Authentication authentication = null;
        try {
            authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginUserDTO.getUserName(), loginUserDTO.getPassword()));
        } catch (ServiceException e) {
            throw new ServiceException(e.getCode(), e.getMessage());
        } catch (BadCredentialsException e) {
            throw new PasswordNotMatchException();
        }
        BaseLoginUser loginUser = (BaseLoginUser) authentication.getPrincipal();
        Map<String, Object> claims = createClaims(loginUser);
        //修改用户信息
        updateUser(loginUser);
        //生成token
        String token = JwtUtils.createJWT(audience.getSeurity(), claims);
        //将token存入redis 并设置过期时间
        redisCache.setCacheObject(JwtUtils.getTokenKey(token), JSON.toJSONString(loginUser), audience.getTtlSecond().intValue(), TimeUnit.SECONDS);
        Map<String, Object> result = new HashMap<>(BaseConstant.NUMBER_ONE);
        result.put(BaseConstant.TOKEN_STR, token);
        return result;
    }


    /**
     * 退出处理
     *
     * @param request 请求信息
     */
    @Override
    public void loginOut(HttpServletRequest request) {
        String header = request.getHeader(BaseConstant.AUTHORIZATION);
        if (StringUtils.hasText(header) && header.startsWith(BaseConstant.BEARER)) {
            String token = header.substring(BaseConstant.BEARER.length());
            String realToken = BaseConstant.PREFIX_TOKEN + token;
            redisCache.deleteObject(realToken);
        }
    }


    /**
     * 封装claims
     *
     * @param loginUser 用户信息
     * @return
     */
    private Map<String, Object> createClaims(BaseLoginUser loginUser) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("userName", loginUser.getUserName());
        claims.put("userId", loginUser.getId());
        claims.put("issuer", audience.getName());
        claims.put("audience", audience.getClient());
        return claims;
    }


    /**
     * 修改用户登录信息
     *
     * @param baseLoginUser 用户信息
     */
    private void updateUser(BaseLoginUser baseLoginUser) {
        SysUserDTO sysUserDTO = new SysUserDTO();
        sysUserDTO.setId(baseLoginUser.getId());
        //sysAdmin.setLoginIp();
        sysUserDTO.setLoginDate(DateTimeUtils.getNowDateTime());
        sysUserDTO.setUpdateBy(baseLoginUser.getUsername());
        sysUserDTO.setUpdateTime(DateTimeUtils.getNowDateTime());
        sysUserMapper.updateUserInfo(sysUserDTO);
    }
}
